/**
 * 
 */
package com.syncshot.androidapp.helper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import android.os.AsyncTask;
import android.util.Log;

import com.syncshot.androidapp.util.Parser;

/**
 * @author Stan
 * 
 */
public class WSHelper {
    /** Used locally to tag Logs */
    private static final String TAG      = "WS";

    public static final String  KEY_BODY = "_body";

    public static class WebserviceCaller extends AsyncTask<Call, Void, Object> {

        private WebserviceCallerListener mListener;
        private Call                     mCall;

        public WebserviceCaller(WebserviceCallerListener listener) {
            mListener = listener;
        }

        public static interface WebserviceCallerListener {
            public abstract void onResult(Call call, Object result);
        }

        @Override
        protected Object doInBackground(Call... params) {
            mCall = params[0];
            String content = call(mCall);
            if (content != null && (mCall.getClassResult() != null)) {
                return Parser.getInstance().deserialize(mCall.getClassResult(), content);
            }
            return content;
        }

        @Override
        protected void onPostExecute(Object result) {
            super.onPostExecute(result);
            if (mListener != null) {
                mListener.onResult(mCall, result);
            }
        }

    }

    public static class Call {
        public static enum CallType {
            POST, GET;
        }

        private CallType            mType;
        private String              mUrl;
        private Class<?>            mClassResult;
        private Map<String, Object> mParameters;

        public Call(CallType type, String url, Class<?> classResult) {
            this(type, url, null, classResult);
        }

        public Call(CallType type, String url, Map<String, Object> parameters, Class<?> classResult) {
            mType = type;
            mUrl = url;
            mParameters = parameters;
            mClassResult = classResult;
        }

        public CallType getType() {
            return mType;
        }

        public String getUrl() {
            return mUrl;
        }

        public Map<String, Object> getParameters() {
            return mParameters;
        }

        public Class<?> getClassResult() {
            return mClassResult;
        }
    }

    public static String call(Call call) {
        switch (call.getType()) {
            case GET:
                return callGET(call);
            case POST:
                return callPOST(call);
            default:
                break;
        }
        return null;
    }

    private static String callPOST(Call call) {

        // Create a new HttpClient and Post Header
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost(call.getUrl());

        try {
            Map<String, Object> map = call.getParameters();
            if (map != null) {
                Object body = map.get(KEY_BODY);
                if (body == null) {
                    // BODY
                    List<NameValuePair> list = getParameters(map);
                    if (list != null) {
                        httppost.setEntity(new UrlEncodedFormEntity(list));
                    }
                } else {
                    httppost.setEntity(new StringEntity(String.valueOf(body), "UTF8"));
                    httppost.setHeader("Content-type", "application/json");
                }
            }

            // Execute HTTP Post Request
            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            String responseBody = httpclient.execute(httppost, responseHandler);
            Log.v(TAG, "responseBodyPOST (" + call.getUrl() + ")  : " + responseBody);

            return responseBody;
        } catch (ClientProtocolException e) {
        	e.printStackTrace();
        } catch (IOException e) {
        	e.printStackTrace();
        }

        return null;
    }

    private static String callGET(Call call) {
        try {
            HttpClient client = new DefaultHttpClient();

            String url = call.getUrl();
            List<NameValuePair> list = getParameters(call.getParameters());
            if (list != null) {
                String paramString = URLEncodedUtils.format(list, "utf-8");
                url = url + paramString;
            }
            HttpGet httpGet = new HttpGet(url);

            // Execute HTTP Post Request
            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            String responseBody = client.execute(httpGet, responseHandler);
            Log.v(TAG, "responseBody GET(" + url + ")  : " + responseBody);
            return responseBody;
        } catch (ClientProtocolException e) {
            Log.w("", e);
        } catch (IOException e) {
            Log.w("", e);
        }
        return null;
    }

    private static List<NameValuePair> getParameters(Map<String, Object> parameters) {
        if (parameters != null) {
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(parameters.size());
            for (String mapKey : parameters.keySet()) {
                nameValuePairs.add(new BasicNameValuePair(mapKey, String.valueOf(parameters.get(mapKey))));
            }
            return nameValuePairs;
        }
        return null;
    }
}
